home *** CD-ROM | disk | FTP | other *** search
/ Aminet 31 / Aminet 31 (1999)(Schatztruhe)[!][Jun 1999].iso / Aminet / dev / cross / z88dk_v1.0s.lha / src / cpp / cpp2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-17  |  20.9 KB  |  607 lines

  1. /*
  2.  *                              C P P 2 . C
  3.  *
  4.  *                         Process #control lines
  5.  *
  6.  * Edit history
  7.  * 13-Nov-84    MM      Split from cpp1.c
  8.  */
  9.  
  10. #include        <stdio.h>
  11. #include        <string.h>
  12. #include        <ctype.h>
  13. #include        "cppdef.h"
  14. #include        "cpp.h"
  15. #if HOST == SYS_VMS
  16. /*
  17.  * Include the rms stuff.  (We can't just include rms.h as it uses the
  18.  * VaxC-specific library include syntax that Decus CPP doesn't support.
  19.  * By including things by hand, we can CPP ourself.)
  20.  */
  21. #include        <nam.h>
  22. #include        <fab.h>
  23. #include        <rab.h>
  24. #include        <rmsdef.h>
  25. #endif
  26.  
  27. /*
  28.  * Generate (by hand-inspection) a set of unique values for each control
  29.  * operator.  Note that this is not guaranteed to work for non-Ascii
  30.  * machines.  CPP won't compile if there are hash conflicts.
  31.  */
  32.  
  33. #define L_assert        ('a' + ('s' << 1))
  34. #define L_define        ('d' + ('f' << 1))
  35. #define L_elif          ('e' + ('i' << 1))
  36. #define L_else          ('e' + ('s' << 1))
  37. #define L_endif         ('e' + ('d' << 1))
  38. #define L_if            ('i' + (EOS << 1))
  39. #define L_ifdef         ('i' + ('d' << 1))
  40. #define L_ifndef        ('i' + ('n' << 1))
  41. #define L_include       ('i' + ('c' << 1))
  42. #define L_line          ('l' + ('n' << 1))
  43. #define L_nogood        (EOS + (EOS << 1))      /* To catch #i          */
  44. #define L_pragma        ('p' + ('a' << 1))
  45. #define L_undef         ('u' + ('d' << 1))
  46. #define L_error         ('e' + ('r' << 1))
  47. #if DEBUG
  48. #define L_debug         ('d' + ('b' << 1))      /* #debug               */
  49. #define L_nodebug       ('n' + ('d' << 1))      /* #nodebug             */
  50. #endif
  51.  
  52. int
  53. control(counter)
  54. int             counter;        /* Pending newline counter              */
  55. /*
  56.  * Process #control lines.  Simple commands are processed inline,
  57.  * while complex commands have their own subroutines.
  58.  *
  59.  * The counter is used to force out a newline before #line, and
  60.  * #pragma commands.  This prevents these commands from ending up at
  61.  * the end of the previous line if cpp is invoked with the -C option.
  62.  */
  63. {
  64.         register int            c;
  65.         register char           *tp;
  66.         register int            hash;
  67.         char                    *ep;
  68.  
  69.         c = skipws();
  70.         if (c == '\n' || c == EOF_CHAR)
  71.             return (counter + 1);
  72.         if (!isdigit(c))
  73.             scanid(c);                  /* Get #word to token[]         */
  74.         else {
  75.             unget();                    /* Hack -- allow #123 as a      */
  76.             strcpy(token, "line");      /* synonym for #line 123        */
  77.         }
  78.         hash = (token[1] == EOS) ? L_nogood : (token[0] + (token[2] << 1));
  79.         switch (hash) {
  80.         case L_assert:  tp = "assert";          break;
  81.         case L_define:  tp = "define";          break;
  82.         case L_elif:    tp = "elif";            break;
  83.         case L_else:    tp = "else";            break;
  84.         case L_endif:   tp = "endif";           break;
  85.         case L_if:      tp = "if";              break;
  86.         case L_ifdef:   tp = "ifdef";           break;
  87.         case L_ifndef:  tp = "ifndef";          break;
  88.         case L_include: tp = "include";         break;
  89.         case L_line:    tp = "line";            break;
  90.         case L_pragma:  tp = "pragma";          break;
  91.         case L_undef:   tp = "undef";           break;
  92.         case L_error:   tp = "error";           break;
  93. #if DEBUG
  94.         case L_debug:   tp = "debug";           break;
  95.         case L_nodebug: tp = "nodebug";         break;
  96. #endif
  97.         default:        hash = L_nogood;
  98.         case L_nogood:  tp = "";                break;
  99.         }
  100.         if (!streq(tp, token))
  101.             hash = L_nogood;
  102.         /*
  103.          * hash is set to a unique value corresponding to the
  104.          * control keyword (or L_nogood if we think it's nonsense).
  105.          */
  106.         if (infile->fp == NULL)
  107.             cwarn("Control line \"%s\" within macro expansion", token);
  108.         if (!compiling) {                       /* Not compiling now    */
  109.             switch (hash) {
  110.             case L_if:                          /* These can't turn     */
  111.             case L_ifdef:                       /*  compilation on, but */
  112.             case L_ifndef:                      /*   we must nest #if's */
  113.                 if (++ifptr >= &ifstack[BLK_NEST])
  114.                     goto if_nest_err;
  115.                 *ifptr = 0;                     /* !WAS_COMPILING       */
  116.             case L_line:                        /* Many                 */
  117.             /*
  118.              * Are pragma's always processed?
  119.              */
  120.             case L_pragma:                      /*  options             */
  121.             case L_include:                     /*   are uninteresting  */
  122.             case L_define:                      /*    if we             */
  123.             case L_undef:                       /*     aren't           */
  124.             case L_assert:                      /*      compiling.      */
  125.             case L_error:                       /*                      */
  126. dump_line:      skipnl();                       /* Ignore rest of line  */
  127.                 return (counter + 1);
  128.             }
  129.         }
  130.         /*
  131.          * Make sure that #line and #pragma are output on a fresh line.
  132.          */
  133.         if (counter > 0 && (hash == L_line || hash == L_pragma)) {
  134.             putchar('\n');
  135.             counter--;
  136.         }
  137.         switch (hash) {
  138.         case L_line:
  139.             /*
  140.              * Parse the line to update the line number and "progname"
  141.              * field and line number for the next input line.
  142.              * Set wrongline to force it out later.
  143.              */
  144.             c = skipws();
  145.             workp = work;                       /* Save name in work    */
  146.             while (c != '\n' && c != EOF_CHAR) {
  147.                 save(c);
  148.                 c = get();
  149.             }
  150.             unget();
  151.             save(EOS);
  152.             /*
  153.              * Split #line argument into <line-number> and <name>
  154.              * We subtract 1 as we want the number of the next line.
  155.              */
  156.             line = atoi(work) - 1;              /* Reset line number    */
  157.             for (tp = work; isdigit(*tp) || type[*tp] == SPA; tp++)
  158.                 ;                               /* Skip over digits     */
  159.             if (*tp != EOS) {                   /* Got a filename, so:  */
  160.                 if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) {
  161.                     tp++;                       /* Skip over left quote */
  162.                     *ep = EOS;                  /* And ignore right one */
  163.                 }
  164.                 if (infile->progname != NULL)   /* Give up the old name */
  165.                     free(infile->progname);     /* if it's allocated.   */
  166.                 infile->progname = savestring(tp);
  167.             }
  168.             wrongline = TRUE;                   /* Force output later   */
  169.             break;
  170.  
  171.         case L_include:
  172.             doinclude();
  173.             break;
  174.  
  175.         case L_define:
  176.             dodefine();
  177.             break;
  178.  
  179.         case L_undef:
  180.             doundef();
  181.             break;
  182.  
  183.         case L_else:
  184.             if (ifptr == &ifstack[0])
  185.                 goto nest_err;
  186.             else if ((*ifptr & ELSE_SEEN) != 0)
  187.                 goto else_seen_err;
  188.             *ifptr |= ELSE_SEEN;
  189.             if ((*ifptr & WAS_COMPILING) != 0) {
  190.                 if (compiling || (*ifptr & TRUE_SEEN) != 0)
  191.                     compiling = FALSE;
  192.                 else {
  193.                     compiling = TRUE;
  194.                 }
  195.             }
  196.             break;
  197.  
  198.         case L_elif:
  199.             if (ifptr == &ifstack[0])
  200.                 goto nest_err;
  201.             else if ((*ifptr & ELSE_SEEN) != 0) {
  202. else_seen_err:  cerror("#%s may not follow #else", token);
  203.                 goto dump_line;
  204.             }
  205.             if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) {
  206.                 compiling = FALSE;              /* Done compiling stuff */
  207.                 goto dump_line;                 /* Skip this clause     */
  208.             }
  209.             doif(L_if);
  210.             break;
  211.  
  212.         case L_if:
  213.         case L_ifdef:
  214.         case L_ifndef:
  215.             if (++ifptr >= &ifstack[BLK_NEST])
  216. if_nest_err:    cfatal("Too many nested #%s statements", token);
  217.             *ifptr = WAS_COMPILING;
  218.             doif(hash);
  219.             break;
  220.  
  221.         case L_endif:
  222.             if (ifptr == &ifstack[0]) {
  223. nest_err:       cerror("#%s must be in an #if", token);
  224.                 goto dump_line;
  225.             }
  226.             if (!compiling && (*ifptr & WAS_COMPILING) != 0)
  227.                 wrongline = TRUE;
  228.             compiling = ((*ifptr & WAS_COMPILING) != 0);
  229.             --ifptr;
  230.             break;
  231.  
  232.         case L_assert:
  233.             if (eval() == 0)
  234.                 cerror("Preprocessor assertion failure", NULLST);
  235.             break;
  236.  
  237.         case L_pragma:
  238.             /*
  239.              * #pragma is provided to pass "options" to later
  240.              * passes of the compiler.  cpp doesn't have any yet.
  241.              */
  242.             printf("#pragma ");
  243.             while ((c = get()) != '\n' && c != EOF_CHAR)
  244.                 cput(c);
  245.             unget();
  246.             cput('\n');
  247.             break;
  248.  
  249.         case L_error:
  250.         {
  251.           char ln[256],*s=ln;
  252.           int c=0;
  253.  
  254.           while (s<(ln+sizeof(ln)-1) && (c=get())!='\n' && c!= EOF_CHAR) { *s=c; ++s; }
  255.           if (c=='\n') unget();
  256.              *s='\0';
  257.             cerror("%s",ln);
  258.             break;
  259.         }
  260.  
  261. #if DEBUG
  262.         case L_debug:
  263.             if (debug == 0)
  264.                 dumpdef("debug set on");
  265.             debug++;
  266.             break;
  267.  
  268.         case L_nodebug:
  269.             debug--;
  270.             break;
  271. #endif
  272.  
  273.         default:
  274.             /*
  275.              * Undefined #control keyword.
  276.              * Note: the correct behavior may be to warn and
  277.              * pass the line to a subsequent compiler pass.
  278.              * This would allow #asm or similar extensions.
  279.              */
  280. //            cerror("Illegal # command \"%s\"", token);
  281.             printf("#%s\n",token);
  282.             break;
  283.         }
  284.         if (hash != L_include) {
  285. #if OLD_PREPROCESSOR
  286.             /*
  287.              * Ignore the rest of the #control line so you can write
  288.              *          #if     foo
  289.              *          #endif  foo
  290.              */
  291.             goto dump_line;                     /* Take common exit     */
  292. #else
  293.             if (skipws() != '\n') {
  294.                 cwarn("Unexpected text in #control line ignored", NULLST);
  295.                 skipnl();
  296.             }
  297. #endif
  298.         }
  299.         return (counter + 1);
  300. }
  301.  
  302. FILE_LOCAL
  303. doif(hash)
  304. int             hash;
  305. /*
  306.  * Process an #if, #ifdef, or #ifndef.  The latter two are straightforward,
  307.  * while #if needs a subroutine of its own to evaluate the expression.
  308.  *
  309.  * doif() is called only if compiling is TRUE.  If false, compilation
  310.  * is always supressed, so we don't need to evaluate anything.  This
  311.  * supresses unnecessary warnings.
  312.  */
  313. {
  314.         register int            c;
  315.         register int            found;
  316.  
  317.         if ((c = skipws()) == '\n' || c == EOF_CHAR) {
  318.             unget();
  319.             goto badif;
  320.         }
  321.         if (hash == L_if) {
  322.             unget();
  323.             found = (eval() != 0);      /* Evaluate expr, != 0 is  TRUE */
  324.             hash = L_ifdef;             /* #if is now like #ifdef       */
  325.         }
  326.         else {
  327.             if (type[c] != LET)         /* Next non-blank isn't letter  */
  328.                 goto badif;             /* ... is an error              */
  329.             found = (lookid(c) != NULL); /* Look for it in symbol table */
  330.         }
  331.         if (found == (hash == L_ifdef)) {
  332.             compiling = TRUE;
  333.             *ifptr |= TRUE_SEEN;
  334.         }
  335.         else {
  336.             compiling = FALSE;
  337.         }
  338.         return;
  339.  
  340. badif:  cerror("#if, #ifdef, or #ifndef without an argument", NULLST);
  341. #if !OLD_PREPROCESSOR
  342.         skipnl();                               /* Prevent an extra     */
  343.         unget();                                /* Error message        */
  344. #endif
  345.         return;
  346. }
  347.  
  348. FILE_LOCAL
  349. doinclude()
  350. /*
  351.  * Process the #include control line.
  352.  * There are three variations:
  353.  *      #include "file"         search somewhere relative to the
  354.  *                              current source file, if not found,
  355.  *                              treat as #include <file>.
  356.  *      #include <file>         Search in an implementation-dependent
  357.  *                              list of places.
  358.  *      #include token          Expand the token, it must be one of
  359.  *                              "file" or <file>, process as such.
  360.  *
  361.  * Note: the November 12 draft forbids '>' in the #include <file> format.
  362.  * This restriction is unnecessary and not implemented.
  363.  */
  364. {
  365.         register int            c;
  366.         register int            delim;
  367. #if HOST == SYS_VMS
  368.         char                    def_filename[NAM$C_MAXRSS + 1];
  369. #endif
  370.  
  371.         delim = macroid(skipws());
  372.         if (delim != '<' && delim != '"')
  373.             goto incerr;
  374.         if (delim == '<')
  375.             delim = '>';
  376.         workp = work;
  377.         instring = TRUE;                /* Accept all characters        */
  378. #ifdef CONTROL_COMMENTS_NOT_ALLOWED
  379.         while ((c = get()) != '\n' && c != EOF_CHAR)
  380.             save(c);                    /* Put it away.                 */
  381.         unget();                        /* Force nl after includee      */
  382.         /*
  383.          * The draft is unclear if the following should be done.
  384.          */
  385.         while (--workp >= work && *workp == ' ')
  386.             ;                           /* Trim blanks from filename    */
  387.         if (*workp != delim)
  388.             goto incerr;
  389. #else
  390.         while ((c = get()) != delim && c != EOF_CHAR)
  391.             save(c);
  392. #endif
  393.         *workp = EOS;                   /* Terminate filename           */
  394.         instring = FALSE;
  395. #if HOST == SYS_VMS
  396.         /*
  397.          * Assume the default .h filetype.
  398.          */
  399.         if (!vmsparse(work, ".H", def_filename)) {
  400.             perror(work);               /* Oops.                        */
  401.             goto incerr;
  402.         }
  403.         else if (openinclude(def_filename, (delim == '"')))
  404.             return;
  405. #else
  406.         if (openinclude(work, (delim == '"')))
  407.             return;
  408. #endif
  409.         /*
  410.          * No sense continuing if #include file isn't there.
  411.          */
  412.         cfatal("Cannot open include file \"%s\"", work);
  413.  
  414. incerr: cerror("#include syntax error", NULLST);
  415.         return;
  416. }
  417.  
  418. FILE_LOCAL int
  419. openinclude(filename, searchlocal)
  420. char            *filename;              /* Input file name              */
  421. int             searchlocal;            /* TRUE if #include "file"      */
  422. /*
  423.  * Actually open an include file.  This routine is only called from
  424.  * doinclude() above, but was written as a separate subroutine for
  425.  * programmer convenience.  It searches the list of directories
  426.  * and actually opens the file, linking it into the list of
  427.  * active files.  Returns TRUE if the file was opened, FALSE
  428.  * if openinclude() fails.  No error message is printed.
  429.  */
  430. {
  431.         register char           **incptr;
  432. #if HOST == SYS_VMS
  433. #if NWORK < (NAM$C_MAXRSS + 1)
  434. #error "<< error, NWORK isn't greater than NAM$C_MAXRSS >>"
  435. #endif
  436. #endif
  437.         char                    tmpname[NWORK]; /* Filename work area   */
  438.  
  439.         if (searchlocal) {
  440.             /*
  441.              * Look in local directory first
  442.              */
  443. #if HOST == SYS_UNIX
  444.             /*
  445.              * Try to open filename relative to the directory of the current
  446.              * source file (as opposed to the current directory). (ARF, SCK).
  447.              */
  448.             if (filename[0] != '/'
  449.              && hasdirectory(infile->filename, tmpname))
  450.                 strcat(tmpname, filename);
  451.             else {
  452.                 strcpy(tmpname, filename);
  453.             }
  454. #else
  455.             if (!hasdirectory(filename, tmpname)
  456.              && hasdirectory(infile->filename, tmpname))
  457.                 strcat(tmpname, filename);
  458.             else {
  459.                 strcpy(tmpname, filename);
  460.             }
  461. #endif
  462.             if (openfile(tmpname))
  463.                 return (TRUE);
  464.         }
  465.         /*
  466.          * Look in any directories specified by -I command line
  467.          * arguments, then in the builtin search list.
  468.          */
  469.         for (incptr = incdir; incptr < incend; incptr++) {
  470.             if (strlen(*incptr) + strlen(filename) >= (NWORK - 1))
  471.                 cfatal("Filename work buffer overflow", NULLST);
  472.             else {
  473. #if HOST == SYS_UNIX
  474.                 if (filename[0] == '/')
  475.                     strcpy(tmpname, filename);
  476.                 else {
  477.                     sprintf(tmpname, "%s/%s", *incptr, filename);
  478.                 }
  479. #else
  480.                 if (!hasdirectory(filename, tmpname))
  481.                     sprintf(tmpname, "%s%s", *incptr, filename);
  482. #endif
  483.                 if (openfile(tmpname))
  484.                     return (TRUE);
  485.             }
  486.         }
  487.         return (FALSE);
  488. }
  489.  
  490. FILE_LOCAL int
  491. hasdirectory(source, result)
  492. char            *source;        /* Directory to examine                 */
  493. char            *result;        /* Put directory stuff here             */
  494. /*
  495.  * If a device or directory is found in the source filename string, the
  496.  * node/device/directory part of the string is copied to result and
  497.  * hasdirectory returns TRUE.  Else, nothing is copied and it returns FALSE.
  498.  */
  499. {
  500. #if HOST == SYS_UNIX
  501.         register char           *tp;
  502.  
  503.         if ((tp = strrchr(source, '/')) == NULL)
  504.             return (FALSE);
  505.         else {
  506.             strncpy(result, source, tp - source + 1);
  507.             result[tp - source + 1] = EOS;
  508.             return (TRUE);
  509.         }
  510. #else
  511. #if HOST == SYS_VMS
  512.         if (vmsparse(source, NULLST, result)
  513.          && result[0] != EOS)
  514.             return (TRUE);
  515.         else {
  516.             return (FALSE);
  517.         }
  518. #else
  519.         /*
  520.          * Random DEC operating system (RSX, RT11, RSTS/E)
  521.          */
  522.         register char           *tp;
  523.  
  524.         if ((tp = strrchr(source, ']')) == NULL
  525.          && (tp = strrchr(source, ':')) == NULL)
  526.             return (FALSE);
  527.         else {
  528.             strncpy(result, source, tp - source + 1);
  529.             result[tp - source + 1] = EOS;
  530.             return (TRUE);
  531.         }
  532. #endif
  533. #endif
  534. }
  535.  
  536. #if HOST == SYS_VMS
  537.  
  538. /*
  539.  * EXP_DEV is set if a device was specified, EXP_DIR if a directory
  540.  * is specified.  (Both set indicate a file-logical, but EXP_DEV
  541.  * would be set by itself if you are reading, say, SYS$INPUT:)
  542.  */
  543. #define DEVDIR (NAM$M_EXP_DEV | NAM$M_EXP_DIR)
  544.  
  545. FILE_LOCAL int
  546. vmsparse(source, defstring, result)
  547. char            *source;
  548. char            *defstring;     /* non-NULL -> default string.          */
  549. char            *result;        /* Size is at least NAM$C_MAXRSS + 1    */
  550. /*
  551.  * Parse the source string, applying the default (properly, using
  552.  * the system parse routine), storing it in result.
  553.  * TRUE if it parsed, FALSE on error.
  554.  *
  555.  * If defstring is NULL, there are no defaults and result gets
  556.  * (just) the node::[directory] part of the string (possibly "")
  557.  */
  558. {
  559.         struct FAB      fab = cc$rms_fab;       /* File access block    */
  560.         struct NAM      nam = cc$rms_nam;       /* File name block      */
  561.         char            fullname[NAM$C_MAXRSS + 1];
  562.         register char   *rp;                    /* Result pointer       */
  563.  
  564.         fab.fab$l_nam = &nam;                   /* fab -> nam           */
  565.         fab.fab$l_fna = source;                 /* Source filename      */
  566.         fab.fab$b_fns = strlen(source);         /* Size of source       */
  567.         fab.fab$l_dna = defstring;              /* Default string       */
  568.         if (defstring != NULLST)
  569.             fab.fab$b_dns = strlen(defstring);  /* Size of default      */
  570.         nam.nam$l_esa = fullname;               /* Expanded filename    */
  571.         nam.nam$b_ess = NAM$C_MAXRSS;           /* Expanded name size   */
  572.         if (sys$parse(&fab) == RMS$_NORMAL) {   /* Parse away           */
  573.             fullname[nam.nam$b_esl] = EOS;      /* Terminate string     */
  574.             result[0] = EOS;                    /* Just in case         */
  575.             rp = &result[0];
  576.             /*
  577.              * Remove stuff added implicitly, accepting node names and
  578.              * dev:[directory] strings (but not process-permanent files).
  579.              */
  580.             if ((nam.nam$l_fnb & NAM$M_PPF) == 0) {
  581.                 if ((nam.nam$l_fnb & NAM$M_NODE) != 0) {
  582.                     strncpy(result, nam.nam$l_node, nam.nam$b_node);
  583.                     rp += nam.nam$b_node;
  584.                     *rp = EOS;
  585.                 }
  586.                 if ((nam.nam$l_fnb & DEVDIR) == DEVDIR) {
  587.                     strncpy(rp, nam.nam$l_dev, nam.nam$b_dev + nam.nam$b_dir);
  588.                     rp += nam.nam$b_dev + nam.nam$b_dir;
  589.                     *rp = EOS;
  590.                 }
  591.             }
  592.             if (defstring != NULLST) {
  593.                 strncpy(rp, nam.nam$l_name, nam.nam$b_name + nam.nam$b_type);
  594.                 rp += nam.nam$b_name + nam.nam$b_type;
  595.                 *rp = EOS;
  596.                 if ((nam.nam$l_fnb & NAM$M_EXP_VER) != 0) {
  597.                     strncpy(rp, nam.nam$l_ver, nam.nam$b_ver);
  598.                     rp[nam.nam$b_ver] = EOS;
  599.                 }
  600.             }
  601.             return (TRUE);
  602.         }
  603.         return (FALSE);
  604. }
  605. #endif
  606.  
  607.